import numpy as np
from bokeh.models import Circle, ColumnDataSource, Label
from bokeh.plotting import figure, Figure

import bitMap


class DrawMap(object):
    area_colors = ["#FFB6C1", "#7B68EE", "#4169E1", "#FFE6D9"]

    def __init__(self):
        pass

    def __del__(self):
        pass

    @classmethod
    def set_color(cls, num):
        # 127未探索
        if num == 127:
            return "#D3D3D3"
        # 0不可通行区域
        if num == 0:
            return "#000000"
        # 255已探索可通行
        if num == 255:
            return "#FFFFFF"
        return cls.area_colors[num % 4]

    @classmethod
    def charge_pos(cls, chargeHandlePos, x_min, y_min, resolution):
        x = (chargeHandlePos[0] / 1000 - x_min) / resolution
        y = (chargeHandlePos[1] / 1000 - y_min) / resolution
        return [x, y]

    @classmethod
    def get_area_pos(cls, map_dict: dict):
        area_list = map_dict.get("area")
        if not area_list:
            return -1
        area_dict = {}
        i = 0
        for area in area_list:
            area_dict[i] = area
            i += 1
        return area_dict

    @classmethod
    def draw_map(cls, map_dict: dict):
        xname = []
        yname = []
        color = []
        values = []
        dict_value_color = {}
        if map_dict.get("MapArray") is None:
            return
        x_range = [str(i) for i in range(map_dict.get("width"))]
        y_range = [str(i) for i in range(map_dict.get("height"))]
        for y, in_array in enumerate(map_dict.get("MapArray")):
            for x, item in enumerate(in_array):
                xname.append(str(x))
                yname.append(str(y))
                values.append(item)
                color.append(cls.set_color(item))
                if item != 0 and item != 127 and item != 255:
                    dict_value_color[item] = cls.set_color(item)

        data = dict(
            xname=xname,
            yname=yname,
            colors=color,
            values=values,
        )
        # create canvas title="Map",
        #                    x_axis_location="above",
        p = figure(tools="hover,save,reset",
                   x_range=x_range, y_range=y_range,
                   tooltips=[('point', '@yname, @xname'), ('value', '@values')])

        p.plot_width = map_dict.get("width") * bitMap.MapScale
        p.plot_height = map_dict.get("height") * bitMap.MapScale
        p.grid.grid_line_color = None
        p.axis.axis_line_color = None
        p.axis.major_tick_line_color = None
        p.axis.major_label_text_font_size = "7px"
        p.axis.major_label_standoff = 0
        p.xaxis.major_label_orientation = np.pi / 3
        #
        p.rect('xname', 'yname', 0.9, 0.9, source=data,
               color='colors', line_color=None, hover_line_color='black', hover_color='color')

        cls.draw_station(map_dict, dict_value_color, p)
        # draw forbid and area
        cls.draw_forbid_area(map_dict, p)
        return p

    @classmethod
    def draw_station(cls, map_dict: dict, dict_color_value: dict, p: Figure):
        circle = Circle(
            size=12,
            fill_color="#cc6633", line_color="#cc6633", fill_alpha=1
        )
        # draw charge
        if map_dict.get("chargeHandleState") != 'notFind':
            circles_source = ColumnDataSource(
                data=dict(
                    x=[cls.charge_pos(map_dict.get("chargeHandlePos"),
                                      map_dict.get("x_min"),
                                      map_dict.get("y_min"),
                                      map_dict.get("resolution"))[0]],
                    y=[cls.charge_pos(map_dict.get("chargeHandlePos"),
                                      map_dict.get("x_min"),
                                      map_dict.get("y_min"),
                                      map_dict.get("resolution"))[1]]
                )
            )
            # add label
            citation = Label(x=75, y=50, x_units='screen', y_units='screen',
                             text='2016-04-01', render_mode='css',
                             border_line_color='black', border_line_alpha=0,
                             background_fill_color='white', background_fill_alpha=0)
            p.add_layout(citation)
            # add comment
            squares_x = [p.plot_width / 3 - 10]
            squares_y = [p.plot_height / 3 - 10]
            for key, value in dict_color_value.items():
                p.square(squares_x, squares_y + (key - 1) * 7, size=6, color=str(value), alpha=1, legend_label=str(key))
            # add charge station
            p.add_glyph(circles_source, circle)
        pass

    @classmethod
    def draw_forbid_area(cls, map_dict: dict, p: Figure):
        forbid_dicts = {}
        # region_dicts = {}
        area_dicts = cls.get_area_pos(map_dict)
        if area_dicts == -1:
            return
        i = 0
        for area_dict in area_dicts.values():
            if area_dict.get("active") == "forbid":
                forbid_dicts[i] = cls.change_region_pos(map_dict, area_dict, area_dict.get("vertexs"))
            # elif area_dict.get("active") == "normal":
            #     region_dicts[i] = cls.change_region_pos(map_dict, area_dict, area_dict.get("vertexs"))
            i += 1
        if len(forbid_dicts) != 0:
            forbid_dict = cls.change_left_right_top_bottom(forbid_dicts)
            p.quad(top=forbid_dict['top'],
                   bottom=forbid_dict['bottom'],
                   left=forbid_dict['left'],
                   right=forbid_dict['right'],
                   color="#E3170D",
                   alpha=0.4)
        # elif len(region_dicts) != 0:
        #     region_dict = cls.change_left_right_top_bottom(region_dicts)
        #     p.quad(top=region_dict['top'],
        #            bottom=region_dict['bottom'],
        #            left=region_dict['left'],
        #            right=region_dict['right'],
        #            color="#C0C0C0",
        #            alpha=0.4)
        pass

    @classmethod
    def change_left_right_top_bottom(cls, area_dicts: dict):
        right = 0
        bottom = 0
        left_list = []
        right_list = []
        top_list = []
        bottom_list = []
        dict_rect = {}
        for forbid_lists in area_dicts.values():
            left = (forbid_lists[0])[0]
            top = (forbid_lists[0])[1]
            for forbid_list in forbid_lists:
                if forbid_list[0] > left:
                    right = forbid_list[0]
                elif forbid_list[0] < left:
                    temp = forbid_list[0]
                    right = left
                    left = temp
                if forbid_list[1] > top:
                    bottom = forbid_list[1]
                elif forbid_list[1] < top:
                    temp = forbid_list[1]
                    bottom = top
                    top = temp

            left_list.append(left)
            right_list.append(right)
            top_list.append(top)
            bottom_list.append(bottom)

        dict_rect['left'] = left_list
        dict_rect['right'] = right_list
        dict_rect['top'] = top_list
        dict_rect['bottom'] = bottom_list
        return dict_rect

    @classmethod
    def change_region_pos(cls, map_dict: dict, area_dict: dict, lists: list):
        list_change = []
        if len(lists) != 0:
            for forbid_list in area_dict.get("vertexs"):
                list_change.append(cls.charge_pos(forbid_list,
                                                  map_dict.get("x_min"),
                                                  map_dict.get("y_min"),
                                                  map_dict.get("resolution")))
        return list_change
